package com.zb.excel.export.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelWriter;
import com.alibaba.excel.support.ExcelTypeEnum;
import com.baomidou.mybatisplus.core.toolkit.Assert;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.zb.entity.*;
import com.zb.excel.*;
import com.zb.excel.export.service.DataExportService;
import com.zb.service.*;
import com.zb.user.service.ConUserService;
import com.zb.utils.ZbManager;
import com.zb.view.ViewGoods;
import com.zb.vo.CodeListSelectVo;
import com.zb.vo.CodeListVo;
import com.zb.vo.GoodsSelectVo;
import com.zb.vo.UserSelectVo;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.BufferedOutputStream;
import java.io.IOException;
import java.net.URLEncoder;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 数据导出服务实现类
 * @Author WEN
 * @Date 2023/9/9 0009
 **/
@Service
public class DataExportServiceImpl implements DataExportService {

    @Resource
    private ZjCodeBatchService codeBatchService;
    @Resource
    private ZjCodeBatchGoodsService codeBatchGoodsService;
    @Resource
    private ZjCodeService codeService;
    @Resource
    private ZjCodeInfoService codeInfoService;
    @Resource
    private ZjUserService userService;
    @Resource
    private ConUserService conUserService;
    @Resource
    private ViewGoodsService viewGoodsService;
    @Resource
    private ZjProductService productService;
    @Resource
    private ZjSpareService spareService;
    @Resource
    private GoodsService goodsService;

    /**
     * Excel每页导出数量
     */
    private static int EXCEL_SHEET_DATA_SIZE = 5000;

    // 根据编码批次ID导出所有编码
    @Override
    public void codeBatchExportExcel(HttpServletResponse response, Long batchId, String suffixExtension) {
        ZjCodeBatch codeBatch = codeBatchService.codeBatchExportById(batchId);
        Assert.isTrue(null != codeBatch, "编码批次参数["+ batchId +"]的数据不存在");
        long count = codeService.getCodeBatchExportTotalByBatchId(batchId);
        Assert.isTrue(count > 0, "编码批次参数["+ batchId +"]的数据没有编码及商品信息");

        List<ZjCodeBatchGoods> batchGoodsList = codeBatchGoodsService.getByBatchId(batchId);

        List<Long> goodsIds = batchGoodsList.stream().map(ZjCodeBatchGoods::getGoodsId).distinct().toList();
        List<Long> goodsSpecIds = batchGoodsList.stream().map(ZjCodeBatchGoods::getGoodsSpecId).distinct().toList();
        List<ViewGoods> viewGoodsList = viewGoodsService.getByGoodsIdsAndGoodsSpecIds(goodsIds, goodsSpecIds);
        ExcelWriter excelWriter = null;
        try {
            excelWriter = EasyExcel.write(response.getOutputStream(), CodeBatchExcel.class)
                    .autoCloseStream(false) // 不要自动关闭，交给 Servlet 自己处理
                    .excelType(ExcelTypeEnum.XLSX)
                    .build();
        } catch (Exception e) { }

        long totalPage = count % EXCEL_SHEET_DATA_SIZE == 0? count / EXCEL_SHEET_DATA_SIZE : count / EXCEL_SHEET_DATA_SIZE +1;
        int page = 1;
        List<ZjCode> codeList = null;
        List<ZjCodeInfo> codeInfos = new ArrayList<>();
        while (page <= totalPage) {
            codeList = codeService.getCodeBatchExportByBatchId(batchId, page, EXCEL_SHEET_DATA_SIZE);
            codeInfos.addAll(codeInfoService.getRegistTimeByIds(codeList.stream().map(ZjCode::getId).toList()));
            List<CodeBatchExcel> codeBatchExcels = codeList.stream().map(code -> {
                CodeBatchExcel codeBatchExcel = new CodeBatchExcel(code).setBatchName(codeBatch.getName()).setBatchCode(codeBatch.getCode());
                viewGoodsList.stream().filter(sv -> Objects.equals(sv.getGoodsType(), codeBatch.getType()) && Objects.equals(code.getGoodsId(), sv.getId()) && Objects.equals(code.getGoodsSpecId(), sv.getSpecId()))
                        .findFirst().ifPresent(specView -> {
                            codeBatchExcel.setBrand(specView.getBrand());
                            codeBatchExcel.setModel(specView.getModel());
                            codeBatchExcel.setGoodsType(specView.getType());
                            codeBatchExcel.setSpecName(specView.getSpecName());
                        });
                codeBatchExcel.setType(codeBatch.getType());
                codeBatchExcel.setRegsiterTime(codeInfos.stream().filter(info -> Objects.equals(code.getId(), info.getId())).map(ZjCodeInfo::getRegisterTime).findFirst().orElse(null));
                return codeBatchExcel;
            }).toList();
            excelWriter.write(codeBatchExcels, EasyExcel.write().sheet(page, "No." + page).build());
            page++;
        }
        try {
            String fieleSuffix = new StringBuilder()
                    .append("filename=")
                    .append("batch_code.")
                    .append(suffixExtension).toString();
            // 注：如使用中文，则需要此行代码配置，如仅使用字母，则可要可不要
            String fieleName = new String(fieleSuffix.getBytes(), "ISO-8859-1");
            response.addHeader("Content-Disposition", fieleName);
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("UTF-8");
            excelWriter.finish();
        } catch (Exception e) {
            ZbManager.log.error("批次编码导出异常：" + e.getMessage());
        }finally {
            try {
                if (null != excelWriter) excelWriter.close();
            }catch (Exception e) { }
        }
    }

    // 编码批次导出文本Txt
    @Override
    public void codeBatchExportTxt(HttpServletResponse response, Long batchId) {
        ZjCodeBatch codeBatch = codeBatchService.codeBatchExportById(batchId);
        Assert.isTrue(null != codeBatch, "编码批次参数["+ batchId +"]的数据不存在");
        long count = codeService.getCodeBatchExportTotalByBatchId(batchId);
        Assert.isTrue(count > 0, "编码批次参数["+ batchId +"]的数据没有编码及商品信息");
        long totalPage = count % EXCEL_SHEET_DATA_SIZE == 0? count / EXCEL_SHEET_DATA_SIZE : count / EXCEL_SHEET_DATA_SIZE +1;
        int page = 1;
        List<String> codes = new ArrayList<>();
        while (page <= totalPage) {
            codes.addAll(codeService.getCodeBatchExportByBatchId(batchId, page, EXCEL_SHEET_DATA_SIZE).stream().map(ZjCode::getSecurityCode).toList());
            page++;
        }
        StringBuilder builder = new StringBuilder();
        for (String code : codes) {
            builder.append(code).append("\r\n");
        }
        BufferedOutputStream buff = null;
        ServletOutputStream outStr = null;
        try {
            String fieleSuffix = new StringBuilder()
                    .append("attachment;filename=")
                    .append("batch_code.txt").toString();
            // 注：如使用中文，则需要此行代码配置，如仅使用字母，则可要可不要
            String fieleName = new String(fieleSuffix.getBytes(), "ISO-8859-1");
            response.addHeader("Content-Disposition", fieleName);
            response.setContentType("text/plain");
            response.setCharacterEncoding("UTF-8");
            outStr = response.getOutputStream();
            buff = new BufferedOutputStream(outStr);
            buff.write(builder.toString().getBytes("UTF-8"));
            buff.flush();
            buff.close();
        } catch (Exception e) {
        }finally {
            if (null != buff) {
                try {
                    buff.close();
                } catch (IOException e) {
                }
            }
            if (null != outStr) {
                try {
                    outStr.close();
                } catch (IOException e) {
                }
            }
        }
    }

    // 客户导出Excel
    @Override
    public void userExportExcel(HttpServletResponse response, Long custAccId, UserSelectVo selectVo) {
        long count = userService.getListCount(custAccId, selectVo);
        Assert.isTrue(count > 0, "当前没有可导出的客户数据");
        long totalPage = count % EXCEL_SHEET_DATA_SIZE == 0? count / EXCEL_SHEET_DATA_SIZE : count / EXCEL_SHEET_DATA_SIZE +1;
        long page = 1;

        ExcelWriter excelWriter = null;
        try {
            excelWriter = EasyExcel.write(response.getOutputStream(), UserExcelExport.class)
                    .autoCloseStream(false) // 不要自动关闭，交给 Servlet 自己处理
                    .excelType(ExcelTypeEnum.XLSX)
                    .build();
        } catch (Exception e) { }

        selectVo.setLimit((long) EXCEL_SHEET_DATA_SIZE);
        List<UserExcelExport> userExcelExportList = null;
        while (page <= totalPage) {
            selectVo.setPage(page);
            userExcelExportList = conUserService.getUserExportExcel(custAccId, selectVo);
            excelWriter.write(userExcelExportList, EasyExcel.write().sheet((int) page, "No." + page).build());
            page++;
        }
        try {
            String fieleSuffix = new StringBuilder()
                    .append("filename=")
                    .append("user_")
                    .append(DateFormatUtils.format(new Date(), "yyyyMMdd"))
                    .append(".xlsx").toString();
            // 注：如使用中文，则需要此行代码配置，如仅使用字母，则可要可不要
            String fieleName = new String(fieleSuffix.getBytes(), "ISO-8859-1");
            response.addHeader("Content-Disposition", fieleName);
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("UTF-8");
            excelWriter.finish();
        } catch (Exception e) {
            ZbManager.log.error("客户档案导出异常：" + e.getMessage());
        }
    }

    // 商品导出Excel
    @Override
    public void goodsExportExcel(HttpServletResponse response, Long custAccId, Integer type, GoodsSelectVo selectVo) {
        long count = viewGoodsService.getGoodsExportExcelCount(custAccId, type, selectVo);
        Assert.isTrue(count > 0, "商品资料没有可导出的数据");
        ExcelWriter excelWriter = null;
        try {
            excelWriter = EasyExcel.write(response.getOutputStream(), GoodsExcelExport.class)
                    .autoCloseStream(false) // 不要自动关闭，交给 Servlet 自己处理
                    .excelType(ExcelTypeEnum.XLSX)
                    .registerWriteHandler(new ExcelFillCellMergeStrategy(new int[]{2, 3, 4, 5}, 1))
                    .build();
        } catch (Exception e) { }

        long totalPage = count % EXCEL_SHEET_DATA_SIZE == 0? count / EXCEL_SHEET_DATA_SIZE : count / EXCEL_SHEET_DATA_SIZE +1;
        selectVo.setLimit((long) EXCEL_SHEET_DATA_SIZE);
        long page = 0;
        List<ViewGoods> viewGoods = null;
        List<GoodsExcelExport> goodsExcelExportList = null;
        while (page < totalPage) {
            page++;
            selectVo.setPage(page);
            viewGoods = viewGoodsService.getGoodsExportExcel(custAccId, type, selectVo);
            goodsExcelExportList = viewGoods.stream().map(goods -> {
                GoodsExcelExport excelExport = new GoodsExcelExport();
                BeanUtil.copyProperties(goods, excelExport);
                excelExport.setGoodsType(type == 1? "成品" : "配件");
                excelExport.setStatus(goods.getDisabled());
                excelExport.setSkuCode(goods.getSpecCode());
                return excelExport;
            }).toList();
            excelWriter.write(goodsExcelExportList, EasyExcel.write().sheet((int)page, "No." + page).build());
        }
        try {
            String fieleSuffix = new StringBuilder()
                    .append("filename=")
                    .append("商品资料.xlsx").toString();
            // 注：如使用中文，则需要此行代码配置，如仅使用字母，则可要可不要
            String fieleName = new String(fieleSuffix.getBytes(), "ISO-8859-1");
            response.addHeader("Content-Disposition", fieleName);
            response.setContentType("application/vnd.ms-excel");
            response.setCharacterEncoding("UTF-8");
            excelWriter.finish();
        } catch (Exception e) {
            ZbManager.log.error("商品资料导出异常：" + e.getMessage());
        }
    }

    // 一物一码导出Excel
    @Override
    public void codeExportExcel(HttpServletResponse response, Long custAccId, CodeListSelectVo selectVo) {
        // 获取商品ID
        List<Long> goodsIds = null;
        if (null != selectVo.getBrandId() || null != selectVo.getTypeId() || StringUtils.isNotBlank(selectVo.getGoods())) {
            GoodsSelect goodsSelect = new GoodsSelect(custAccId, selectVo.getBrandId(), selectVo.getTypeId(), selectVo.getGoods());
            goodsSelect.setPage(selectVo.getPage());
            goodsSelect.setLimit(selectVo.getLimit());

            if (null == selectVo.getType()) {
                goodsIds = goodsService.pageGetGoodsIds(goodsSelect);
                if (goodsIds.isEmpty()) goodsIds.add(-1L);
            }
            if (null != selectVo.getType() && 1 == selectVo.getType()) {
                goodsIds = productService.pageGetIds(goodsSelect);
                if (goodsIds.isEmpty()) goodsIds.add(-1L);
            }
            if (null != selectVo.getType() && 2 == selectVo.getType()) {
                goodsIds = spareService.pageGetIds(goodsSelect);
                if (goodsIds.isEmpty()) goodsIds.add(-1L);
            }
        }
        long totalCount = codeService.getListCount(custAccId, goodsIds, selectVo);
        Assert.isTrue(totalCount > 0, "一物一码没有可导出的数据");
        ExcelWriter excelWriter = null;
        try {
            excelWriter = EasyExcel.write(response.getOutputStream(), CodeExportExcel.class)
                    .autoCloseStream(false) // 不要自动关闭，交给 Servlet 自己处理
                    .excelType(ExcelTypeEnum.XLSX)
                    .build();
        } catch (Exception e) { }

        long totalPage = totalCount % EXCEL_SHEET_DATA_SIZE == 0? totalCount / EXCEL_SHEET_DATA_SIZE : totalCount / EXCEL_SHEET_DATA_SIZE +1;
        long page = 1;
        selectVo.setLimit((long) EXCEL_SHEET_DATA_SIZE);
        List<CodeListVo> listData = null;
        List<CodeExportExcel> exportExcelList = null;
        while (page <= totalPage) {
            selectVo.setPage(page);
            listData = codeService.getListData(custAccId, goodsIds, selectVo);
            exportExcelList = listData.stream().map(vo -> {
                CodeExportExcel exportExcel = new CodeExportExcel();
                BeanUtil.copyProperties(vo, exportExcel);
                BeanUtil.copyProperties(vo, exportExcel);
                exportExcel.setCode(vo.getSecurityCode());
                exportExcel.setActiveStatus(vo.getActiva()? "已激活" : "未激活");
                exportExcel.setCodeStatus(vo.getStatus());
                return exportExcel;
            }).toList();
            excelWriter.write(exportExcelList, EasyExcel.writerSheet((int) page, "No." + page).build());
            page++;
        }
        try {
//            response.addHeader("Content-Disposition", "filename=code_"+ DateFormatUtils.format(new Date(), "yyyyMMdd") +".xlsx");
//            response.setContentType("application/vnd.ms-excel");
//            response.setCharacterEncoding("UTF-8");

            response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
            response.setCharacterEncoding("UTF-8");
            String fileName = URLEncoder.encode("编码档案", "UTF-8").replaceAll("\\+", "%20");
            response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
            excelWriter.finish();
        } catch (Exception e) {
            ZbManager.log.error("一物一码资料导出异常：" + e.getMessage());
        }
    }
}
